import spinal.core._
import spinal.lib._

class timer extends Component {
  val io = new Bundle {
    val enable = in Bool()
    val clear = in Bool()
    val mode = in UInt(4 bits)
    val period = in UInt(32 bits)
    val pulse_num = in UInt(16 bits)
    val timeout_flag = out Bool()
  }
  noIoPrefix()

  val flag = Reg(Bool()) init(False)

  val counter = Reg(UInt(32 bits)) init(0)
  when( io.mode === U"4'0000" ){
    when(counter < io.period){
      counter := counter + 1
      }.otherwise{
        counter := 0
      }
      }.elsewhen (io.mode === U"5'0001"){
        when(io.enable){
          when(counter < io.period){
            counter := counter + 1
          }
        }

        }.elsewhen (io.mode === U"4'0010"){
          flag.setWhen(io.enable.rise)
 
          when(flag)
          {
            when(counter < io.period){
              counter := counter + 1
            }.otherwise
            {
                   flag.clear()
            }
          }
          }.elsewhen (io.mode === U"4'0011"){
            when(io.enable){
              when(io.clear){
                counter := 0
                }.otherwise {
                  when(counter < io.period)
                  {
                    counter := counter + 1
                  }.otherwise{
                    counter := 0
                  }
                }
                }.otherwise{
                  counter := 0
                }
          }

      when(counter >= io.period - io.pulse_num && counter < io.period)
      {
        io.timeout_flag := True
      }.otherwise
      {
        io.timeout_flag := False
      }
}
 
object timerVerilog {
  def main(args: Array[String]) {
    SpinalConfig( targetDirectory = "." ).generateVerilog( new timer )
  }
}
